<?php

namespace App\Services;

use App\Common\Libs\ArrayHelper;
use App\Common\Libs\Dispatch\Queue;
use App\Common\Libs\IdBuilder;
use App\Consts\GlobalCacheConst;
use App\Consts\GlobalConst;
use App\Consts\GlobalCounterConst;
use App\Consts\GlobalLikeConst;
use App\Consts\GlobalNoteConst;
use App\Consts\GlobalQueueConst;
use App\Events\CacheCounterEvent;
use App\Events\Like\CancelLikeEvent;
use App\Events\Like\CreateLikeEvent;
use App\Exceptions\Error;
use App\Formats\LikeFormat;
use App\Jobs\Controller\LikeJob;
use App\Models\Cache\Cache;
use App\Models\Cache\CacheKey;
use App\Models\UserMessageLikeSend;
use Illuminate\Support\Facades\DB;

/**
 * @package App\Services
 * @see LikeService
 */
class LikeService extends BaseService
{
    private $_repository;

    public function __construct()
    {
        parent::__construct();
        $this->_repository = repository()->LikeRepository;
    }

    public function getUserLikeList($searchParams)
    {
        $dataProvider = $this->_repository->getUserLikeList($searchParams);
        $pagination = $this->getPagination();
        $likes = $dataProvider->get();

        $list = formats()->LikeFormat->formatLikeList($likes, $searchParams['current_user_id'], LikeFormat::USER_LIKE_LIST);

        return self::outputMoreList($dataProvider, $pagination, $list);
    }

    /**
     * 新增点赞
     * @param $loadData
     * @return bool|\Illuminate\Http\JsonResponse
     */
    public function createLike($loadData)
    {
        // 私密笔记不可点赞
        if ($loadData['target_type'] == GlobalConst::TARGET_TYPE_NOTE) {
            $note = repository()->NoteRepository->getNoteById($loadData['target_id']);
            if ((!$note || ($note && $note->is_deleted == GlobalConst::IS_DELETED) || ($note && $note->is_public == GlobalNoteConst::IS_NOT_PUBLIC)) && $loadData['sender_id'] != $note->user_id) {
                return Error::handle(lang('Note is disable'));
            }
            $loadData['note_type'] = $note->type;
        }

        // 点赞评论，如果其主体笔记是私密/已删除不可点赞
        if ($loadData['target_type'] == GlobalConst::TARGET_TYPE_COMMENT) {
            $comment = repository()->CommentRepository->getComment($loadData['target_id']);
            $note = repository()->NoteRepository->getNoteById($comment->target_id);
            if ((!$note || ($note && $note->is_deleted == GlobalConst::IS_DELETED) || ($note && $note->is_public == GlobalNoteConst::IS_NOT_PUBLIC)) && $loadData['sender_id'] != $note->user_id) {
                return Error::handle(lang('Note is disable'));
            }
        }

        // 点赞回复，如果其主体是笔记私密/已删除不可点赞
        if ($loadData['target_type'] == GlobalConst::TARGET_TYPE_REPLY) {
            $reply = repository()->ReplyRepository->getReplyByReplyId($loadData['target_id']);
            $note = repository()->NoteRepository->getNoteById($reply->target_id);
            if ((!$note || ($note && $note->is_deleted == GlobalConst::IS_DELETED) || ($note && $note->is_public == GlobalNoteConst::IS_NOT_PUBLIC)) && $loadData['sender_id'] != $note->user_id) {
                return Error::handle(lang('Note is disable'));
            }
            if ($reply && $reply->comment->is_deleted == GlobalConst::IS_DELETED) {
                return Error::handle(lang('Comment is disable'));
            }
        }

        // 防止连点
        $alreadyLike = $this->judgeAlreadyLikeOrCancelFromCache($loadData['sender_id'], $loadData['target_id']);
        if ($alreadyLike) {
            return true;
        }

        DB::beginTransaction();
        try {
            // 缓存没有命中，查看点赞记录是否存在
            $msgLikeSend = $this->_repository->getLikeSendBySenderIdAndTargetId($loadData['sender_id'], $loadData['target_id']);
            if ($msgLikeSend) {
                // 用户已经点赞，更新用户点赞缓存以防止重复点赞
                if ($msgLikeSend->is_deleted == GlobalConst::IS_NOT_DELETE) {
                    $this->saveUserLikeToCache($msgLikeSend);
                    return true;
                }
                // 用户取消了点赞，更新【我收到的点赞】【我发出的点赞】记录
                $receiveId = $this->getLikeTargetUserId($loadData['target_id'], $loadData['target_type']);
                $msgLikeReceive = $this->_repository->getLikeReceiveByReceiveIddAndTargetId($receiveId, $loadData['target_id']);
                $this->_repository->updateLikeSend($msgLikeSend, ['is_deleted' => GlobalConst::IS_NOT_DELETE]);
                if ($msgLikeReceive) {
                    $this->_repository->updateLikeReceive($msgLikeReceive, ['is_deleted' => GlobalConst::IS_NOT_DELETE]);
                }
            } else {
                $receiveId = $this->getLikeTargetUserId($loadData['target_id'], $loadData['target_type']);
                $sendLoadData = ArrayHelper::merge($loadData, [
                    'receive_id' => $receiveId,
                    'message_id' => IdBuilder::getUniqueID(),
                    'is_deleted' => GlobalConst::IS_NOT_DELETE
                ]);

                $receiveLoadData = ArrayHelper::merge($loadData, [
                    'receive_id' => $receiveId,
                    'message_id' => IdBuilder::getUniqueID(),
                    'is_deleted' => GlobalConst::IS_NOT_DELETE
                ]);

                // 新增【我发出的点赞】
                $msgLikeSend = $this->_repository->createLikeSend($sendLoadData);
                if (!$msgLikeSend) {
                    return Error::handle();
                }
                // 新增【我收到的点赞】
                if ($loadData['sender_id'] != $receiveLoadData['receive_id']) {
                    $msgLikeReceive = $this->_repository->createLikeReceive($receiveLoadData);
                    if (!$msgLikeReceive) {
                        return Error::handle();
                    }
                }
            }

            // 同步更新主体计数
            $this->syncCounterFromCache($loadData['target_id'], $loadData['target_type']);

            // 更新用户点赞缓存以防止重复点赞
            $this->saveUserLikeToCache($msgLikeSend);

            /**
             * 队列做以下几件事：
             *  1. 更新用户未读消息数 - 点赞+1
             *  2. 记录日志
             *  3. 【暂时】如果赞的是评论，要修改评论的<hot> +1
             *  4. 静态化【我收到的赞】
             */
            CreateLikeEvent::dispatch($msgLikeSend);

            DB::commit();

            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            return Error::handle(lang('Unstable network'));
        }
    }

    /**
     * 取消点赞
     * @param $loadData
     * @return bool|\Illuminate\Http\JsonResponse
     */
    public function cancelLike($loadData)
    {
        // 防止连点
        $alreadyCancelLike = $this->judgeAlreadyLikeOrCancelFromCache($loadData['sender_id'], $loadData['target_id'], true);
        if ($alreadyCancelLike) {
            return true;
        }

        DB::beginTransaction();
        try {
            // 用户已经取消点赞，更新用户点赞缓存以防止重复点赞
            $msgLikeSend = $this->_repository->getLikeSendBySenderIdAndTargetId($loadData['sender_id'], $loadData['target_id']);
            if ($msgLikeSend && $msgLikeSend->is_deleted == GlobalConst::IS_DELETED) {
                $this->saveUserCancelLikeToCache($msgLikeSend);
                return true;
            }

            // 更新【我发出的点赞】记录
            $this->_repository->updateLikeSend($msgLikeSend, ['is_deleted' => GlobalConst::IS_DELETED]);

            // 更新【我收到的点赞】记录
            $receiveId = $this->getLikeTargetUserId($loadData['target_id'], $loadData['target_type']);
            $msgLikeReceive = $this->_repository->getLikeReceiveByReceiveIddAndTargetId($receiveId, $loadData['target_id']);
            if ($msgLikeReceive) {
                $this->_repository->updateLikeReceive($msgLikeReceive, ['is_deleted' => GlobalConst::IS_DELETED]);
            }

            // 同步更新主体计数
            $this->syncCounterFromCache($loadData['target_id'], $loadData['target_type'], GlobalCounterConst::DECREASE);

            // 更新用户点赞缓存以防止重复点赞
            $this->saveUserLikeToCache($msgLikeSend);

            /**
             * 队列做以下几件事：
             *  1. 更新用户未读消息数 - 点赞 -1
             *  2. 记录日志
             *  3. 【暂时】如果赞的是评论，要修改评论的<hot> -1
             */
            CancelLikeEvent::dispatch($msgLikeReceive);

            DB::commit();

            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            return Error::handle(lang('Unstable network'));
        }
    }

    /**
     * 更新用户点赞缓存以防止重复点赞
     *  1.点赞信息入缓存
     *  2.清除取消点赞信息缓存
     * @param UserMessageLikeSend $msgLikeSend
     * @return bool
     */
    public function saveUserLikeToCache($msgLikeSend)
    {
        Cache::getInstance([
            'user_id' => $msgLikeSend->sender_id,
            'target_id' => $msgLikeSend->target_id,
        ])->set(CacheKey::LIKE_USER_TARGET, true, GlobalCacheConst::EXPIRED_SIXTY);

        Cache::getInstance([
            'user_id' => $msgLikeSend->sender_id,
            'target_id' => $msgLikeSend->target_id,
        ])->delete(CacheKey::CANCEL_LIKE_USER_TARGET);

        return true;
    }

    /**
     * 更新用户取消点赞缓存
     *  1.清除点赞信息缓存
     *  2.取消点赞信息入缓存
     * @param UserMessageLikeSend $msgLikeSend
     * @return bool
     */
    public function saveUserCancelLikeToCache($msgLikeSend)
    {
        Cache::getInstance([
            'user_id' => $msgLikeSend->sender_id,
            'target_id' => $msgLikeSend->target_id,
        ])->set(CacheKey::CANCEL_LIKE_USER_TARGET, true, GlobalCacheConst::EXPIRED_SIXTY);

        Cache::getInstance([
            'user_id' => $msgLikeSend->sender_id,
            'target_id' => $msgLikeSend->target_id,
        ])->delete(CacheKey::LIKE_USER_TARGET);

        return true;
    }

    /**
     * 同步评论主体的缓存计数
     * @param string $targetId
     * @param int $targetType
     * @param int $trend
     * @return bool
     */
    public function syncCounterFromCache($targetId, $targetType, $trend = GlobalCounterConst::INCREASE)
    {
        $data = [];
        if ($targetType == GlobalConst::TARGET_TYPE_NOTE) {
            $data = [
                'key_params' => ['note_id' => $targetId],
                'cache_key' => CacheKey::COUNTER_NOTE,
                'values' => GlobalCounterConst::COUNT_LIKE,
                'trend' => $trend
            ];
        }

        if ($targetType == GlobalConst::TARGET_TYPE_COMMENT) {
            $data = [
                'key_params' => ['comment_id' => $targetId],
                'cache_key' => CacheKey::COUNTER_COMMENT,
                'values' => GlobalCounterConst::COUNT_LIKE,
                'trend' => $trend
            ];
        }

        if ($targetType == GlobalConst::TARGET_TYPE_REPLY) {
            $data = [
                'key_params' => ['reply_id' => $targetId],
                'cache_key' => CacheKey::COUNTER_REPLY,
                'values' => GlobalCounterConst::COUNT_LIKE,
                'trend' => $trend
            ];
        }

        if ($targetType == GlobalConst::TARGET_TYPE_DYNAMIC) {
            $data = [
                'key_params' => ['dynamic_id' => $targetId],
                'cache_key' => CacheKey::COUNTER_DYNAMIC,
                'values' => GlobalCounterConst::COUNT_LIKE,
                'trend' => $trend
            ];
        }

        if ($data) {
            CacheCounterEvent::dispatch($data);
        }

        return true;
    }

    /**
     * 从缓存中验证用户对主体是否点过赞，或取消过点赞
     * @param $userId
     * @param $targetId
     * @param false $isCancel
     * @return mixed
     */
    public function judgeAlreadyLikeOrCancelFromCache($userId, $targetId, $isCancel = false)
    {
        $keyParams = [
            'user_id' => $userId,
            'target_id' => $targetId,
        ];
        if ($isCancel) {
            $cacheKey = CacheKey::CANCEL_LIKE_USER_TARGET;
        } else {
            $cacheKey = CacheKey::LIKE_USER_TARGET;
        }

        return Cache::getInstance($keyParams)->get($cacheKey);
    }

    /**
     * 通过【主体类型】获取用户点赞列表
     * @param $userId
     * @param $targetType
     * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
     */
    public function getLikeListByTargetType($userId, $targetType)
    {
        return repository()->LikeRepository->getLikeListByTargetType($userId, $targetType);
    }

    /**
     * 获取点赞的主体的用户
     * @param $targetId
     * @param $targetType
     * @return bool|string
     */
    public function getLikeTargetUserId($targetId, $targetType)
    {
        $receiveUserId = '';
        if ($targetType == GlobalConst::TARGET_TYPE_NOTE) {
            $note = repository()->NoteRepository->getNoteByNoteId($targetId);
            if ($note) {
                $receiveUserId = $note['user_id'];
            }
        }

        if ($targetType == GlobalConst::TARGET_TYPE_COMMENT) {
            $comment = repository()->CommentRepository->getComment($targetId);
            if ($comment) {
                $receiveUserId = $comment['user_id'];
            }
        }

        if ($targetType == GlobalConst::TARGET_TYPE_REPLY) {
            $reply = repository()->ReplyRepository->getReplyByReplyId($targetId);
            if ($reply) {
                $receiveUserId = $reply['user_id'];
            }
        }

        if ($targetType == GlobalConst::TARGET_TYPE_DYNAMIC) {
            $dynamic = repository()->DynamicRepository->getDynamicById($targetId);
            if ($dynamic) {
                $receiveUserId = $dynamic['user_id'];
            }
        }

        return $receiveUserId ?? false;
    }

    /**
     * 判断用户是否点赞
     * @param $userId
     * @param $targetId
     * @return int
     */
    public function judgeUserIsLiked($userId, $targetId)
    {
        $like = $this->_repository->getLikeSendBySenderIdAndTargetId($userId, $targetId);
        return $like && $like->is_deleted == GlobalConst::IS_NOT_DELETE ? GlobalLikeConst::USER_IS_LIKED : GlobalLikeConst::USER_NOT_LIKE;
    }

    /**
     * 删除笔记后，要
     *  1.[user_message_like_send_]表软删除
     *  2.[user_message_like_receive_]表软删除
     *  3.[log_count_]表新增所有用户取消点赞记录
     *  4.更新笔记的点赞数
     * @param $queueMessageBody
     */
    public function deletedNoteToDelLikeByQueue($queueMessageBody)
    {
        return Queue::getInstance(LikeJob::class)
            ->push($queueMessageBody, GlobalQueueConst::LIKE_CANCEL_BY_NOTE);
    }

}
